﻿using System;
using System.Collections.Generic;
using System.Reflection;
using System.Linq;
using CoreEx.Database.Linq.Translators;
using CoreEx.Database.Metadata;
using CoreEx.Database.Query.Expressions;

namespace CoreEx.Database.Linq
{
    /// <summary>
    /// Represents a table source in the final query that is
    /// used to navigate the <see cref="TargetMember"/>
    /// </summary>
    public class TableSource
    {                
        /// <summary>
        /// Initializes a new instance of the <see cref="TableSource"/> class.
        /// </summary>
        public TableSource(ITypeMappingInfo typeMappingInfo)
        {
            JoinedTableSources = new List<TableSource>();
            TableInfo = typeMappingInfo.TableInfo;            
            MappedProperties =
                typeMappingInfo.ColumnMappings.Values.Where(c => c.ColumnInfo != null || c.ForeignKeyInfo != null).
                    Select(c => new MappedProperty(c, this)).ToDictionary(pm => pm.PropertyMappingInfo.Property);
        }

         /// <summary>
        /// Gets or sets the target member (<see cref="Type"/> or <see cref="PropertyInfo"/>) for this <see cref="TableSource"/>
        /// </summary>        
        public MemberInfo TargetMember { get; set; }

        /// <summary>
        /// Gets or sets the alias used for this <see cref="TableSource"/>
        /// </summary>
        public string Alias { get; set; }

        /// <summary>
        /// Gets or sets the <see cref="TableInfo"/> instance that 
        /// describes the metadata for this <see cref="TableSource"/>
        /// </summary>
        public TableInfo TableInfo { get; set; }

        /// <summary>
        /// Gets a list of <see cref="IPropertyMappingInfo"/> instances 
        /// that represents the mapping between a table column and a property.
        /// </summary>
        public IDictionary<PropertyInfo,MappedProperty> MappedProperties { get; private set; }
      
        /// <summary>
        /// Returns a list of <see cref="TableSource"/> instances 
        /// that represents tables that are joined with this <see cref="TableSource"/>
        /// </summary>
        public IList<TableSource> JoinedTableSources { get; private set; }


        /// <summary>
        /// Gets or sets the <see cref="TableSource"/> that represents the left hand side 
        /// of a join expression where this instance represents the right hand side.
        /// </summary>
        public TableSource OuterTableSource { get; set; }


        /// <summary>
        /// Gets the <see cref="Projection"/> instance that represents the columns 
        /// that is projected from this <see cref="TableSource"/>.
        /// </summary>
        public Projection Projection { get; set; }
        
        /// <summary>
        /// Gets a list of column names that represents the primary key columns as they are projected from the query.
        /// </summary>
        /// <remarks>
        /// When a query joins multiple tables that have the same primary key column name, the projection will make each 
        /// primary key column unique. E.g. t0.PrimaryId, t1.PrimaryId1 
        /// </remarks>
        public string[] PrimaryKeyColumnNames { get; set; }

        
        /// <summary>
        /// Gets or sets the <see cref="DbExpression"/> that represents the <see cref="DbTableExpression"/>
        /// or the <see cref="DbJoinExpression"/> to be included in the final query in order to either 
        /// project columns from this table or filter the result based on columns from this table.
        /// </summary>
        public DbExpression TableExpression { get; set;}


        /// <summary>
        /// Gets or sets the <see cref="TranslateResult"/> that this <see cref="TableSource"/> belongs to.
        /// </summary>
        public TranslateResult TranslateResult { get; set; }


        public override string ToString()
        {
            return TableInfo.TableName;
        }
    }
}
